﻿using System;
using System.Data;
using System.Configuration;
using TA.JSON;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Text;
using System.IO;

using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// Base class for all Turbo controls.
	/// </summary>
	public class TControl : BaseControl, IAttributeAccessor, IEventHandler, IHasControlState
	{
		#region STATIC
		/// <summary>
		/// Prepends the provided event script with some other script and returns the result.
		/// </summary>
		/// <param name="eventScript">The event script to be completed.</param>
		/// <param name="otherScript">The other script to be inserted before the event script.</param>
		/// <returns></returns>
		public static string GetEventScript(string eventScript, string otherScript)
		{
			StringBuilder sb = new StringBuilder();

			otherScript = (otherScript ?? "").Trim();
			if (!string.IsNullOrEmpty(otherScript))
				sb.AppendFormat("{0};", otherScript);

			sb.Append(eventScript);
			return sb.ToString();
		}
		/// <summary>
		/// Checks if the specified string is a name of a form element tag.
		/// </summary>
		/// <param name="p"></param>
		/// <returns>True if the string is a form element tag name; otherwise, false.</returns>
		public static bool IsFormElementTag(string tagName)
		{
			return
				string.Equals(tagName, "INPUT", StringComparison.InvariantCultureIgnoreCase)
				|| string.Equals(tagName, "TEXTAREA", StringComparison.InvariantCultureIgnoreCase)
				|| string.Equals(tagName, "SELECT", StringComparison.InvariantCultureIgnoreCase);
		}
		#endregion
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		/// <param name="tag"></param>
		public TControl(HtmlTextWriterTag tag)
		{
			Tag = tag;
		}
		#endregion
		#region PROPS
		#region DEF
		/// <summary>
		/// Creates a Properties object by appending an enumeration of properties to an existing Properties object.
		/// </summary>
		/// <param name="orig">The Properties object to append the properties to, or null to create a new one.</param>
		/// <param name="properties">The enumeration of properties to be appended.</param>
		/// <returns>The Properties object which contains the original object and the appended properties.</returns>
		protected static Properties Define(Properties orig, params IEnumerable<BasePropertyDefinition>[] properties)
		{
			Properties res = new Properties();
			if (orig != null)
			{
				foreach (string key in orig.Keys)
					res[key] = orig[key];
			}
			foreach (IEnumerable<BasePropertyDefinition> propSet in properties)
			{
				foreach (BasePropertyDefinition pd in propSet)
				{
#if DEBUG
					foreach (BasePropertyDefinition pdExisting in res.Values)
					{
						if (string.Equals(pdExisting.ShortName, pd.ShortName))
							throw new InvalidOperationException(string.Format("Properties {0} and {1} have the same short name {2}.", pd.Name, pdExisting.Name, pd.ShortName));
					}
#endif
					res[pd.Name] = pd;
				}
			}

			return res;
		}
		/// <summary>
		/// Props.
		/// </summary>
		protected static Properties _clientProperties = Define(null,
			new BasePropertyDefinition[] { 
				new PropertyDefinition<bool>("Enabled", "E", true) { IsHTML = true },
				new PropertyDefinition<bool>("Shown", "W", true) { IsHTML = true },
				//new PropertyDefinition<bool>("Visible", "V", true) { IsHTML = true },
				new CssClassPropertyDefinition(),
				new StylePropertyDefinition(),
				new PropertyDefinition<short>("TabIndex", "I", (short)0) { IsHTML = true },
				new PropertyDefinition<string>("ToolTip", "T", "") { IsHTML = true },
			});
		/// <summary>
		/// When overridden, gets the Properties object describing all of the properties for a control.
		/// </summary>
		[Browsable(false)]
		public virtual Properties ClientProperties
		{
			get
			{
				return _clientProperties;
			}
		}
		/// <summary>
		/// Gets a dictionary (hash table) which allows resolution of property definitions by their respective short names (JSON serialization).
		/// </summary>
		protected Dictionary<string, BasePropertyDefinition> ClientPropertiesShort
		{
			get
			{
				Dictionary<string, BasePropertyDefinition> res = new Dictionary<string, BasePropertyDefinition>();
				foreach (BasePropertyDefinition pd in ClientProperties.Values)
					res[pd.ShortName] = pd;
				return res;
			}
		}
		#endregion
		/// <summary>
		/// Gets or sets the HtmlTextWriterTag of this control.
		/// </summary>
		[Category("Appearance")]
		[DefaultValue(HtmlTextWriterTag.Unknown)]
		public virtual HtmlTextWriterTag Tag
		{
			get
			{
				try
				{
					return (HtmlTextWriterTag)Enum.Parse(typeof(HtmlTextWriterTag), TagString);
				}
				catch
				{
					return HtmlTextWriterTag.Unknown;
				}
			}
			set
			{
				TagString = value.ToString();
			}
		}
		/// <summary>
		/// Gets the attribute collection to be applied to the HTML tag for this control.
		/// </summary>
		[DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
		[Category("Behavior")]
		public System.Web.UI.AttributeCollection Attributes { get { return _attributes; } }
		/// <summary>
		/// Gets the style collection to be applied to this control.
		/// </summary>
		[DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
		[Browsable(false)]
		[Category("Appearance")]
		public CssStyleCollection Style { get { return _attributes.CssStyle; } }
		/// <summary>
		/// If false, the control is disabled. 
		/// </summary>
		/// <remarks>
		/// For HTML field elements (INPUT, SELECT and TEXTAREA), settings this to false adds a "disabled" attribute.
		/// For controls that render other HTML elements, behavior depends on the control.
		/// </remarks>
		[DefaultValue(true)]
		[Category("Behavior")]
		public virtual bool Enabled
		{
			get
			{
				return GetProperty<bool>("Enabled");
			}
			set
			{
				ViewState["Enabled"] = value;
			}
		}
		/// <summary>
		/// The tab index of this control. Use this to override the default tabbing sequence.
		/// </summary>
		/// <remarks>
		/// For HTML field elements (INPUT, SELECT and TEXTAREA), settings this to a non-zero number adds a "tabindex" attribute with the appropriate value.
		/// For controls that render other HTML elements, behavior depends on the control.
		/// </remarks>
		[DefaultValue((short)0)]
		[Category("Behavior")]
		public short TabIndex
		{
			get
			{
				return GetProperty<short>("TabIndex");
			}
			set
			{
				ViewState["TabIndex"] = value;
			}
		}
		///// <summary>
		///// Gets or sets a flag indicating whether this control is rendered as UI on the page.
		///// </summary>
		//[DefaultValue(true)]
		//public override bool Visible
		//{
		//  get
		//  {
		//    return this._visible;
		//  }
		//  set
		//  {
		//    this._visible = value;
		//  }
		//}
		//{
		//  get
		//  {
		//    return GetProperty<bool>("Visible");
		//  }
		//  set
		//  {
		//    ViewState["Visible"] = value;
		//  }
		//}
		/// <summary>
		/// Gets or sets shown status of this control.
		/// </summary>
		/// <remarks>
		/// The behavior of this is slightly different from that of the standard ASP.NET Visible property.
		/// If it's set to false, the behavior depends on the JavaScript status. 
		/// If JavaScript is confirmed to be unavailable (<see cref="TPage.JavaScript"/> == false),
		/// then setting this property to false prevents this control from being rendered, just like in ASP.NET WebForms when Visible is false.
		/// Otherwise, the control is rendered with "display:none;" style applied to it. This is done so that
		/// the control can be made visible on the client side without a trip to the server.
		/// </remarks>
		[DefaultValue(true)]
		public virtual bool Shown
		{
			get
			{
				return GetProperty<bool>("Shown");
			}
			set
			{
				ViewState["Shown"] = value;
			}
		}
		///// <summary>
		///// Gets or sets a flag indicating whether this control is rendered as UI on the page.
		///// </summary>
		//public bool Rendered { get; set; }
		/// <summary>
		/// The text of the tooltip.
		/// </summary>
		/// <remarks>
		/// If it's set to a non-empty string value, it adds a "title" attribute with the appropriate value.
		/// </remarks>
		[DefaultValue("")]
		[Category("Appearance")]
		public string ToolTip
		{
			get
			{
				return GetProperty<string>("ToolTip");
			}
			set
			{
				ViewState["ToolTip"] = value;
			}
		}
		/// <summary>
		/// The CSS class to be applied to this control.
		/// </summary>
		[DefaultValue("")]
		[CssClassProperty]
		[Category("Appearance")]
		public virtual string CssClass
		{
			get
			{
				return Attributes["class"];
			}
			set
			{
				Attributes["class"] = value;
			}
		}
		/// <summary>
		/// Gets true if this control is able to receive focus on the client, otherwise false.
		/// </summary>
		[Browsable(false)]
		public virtual bool CanReceiveFocus
		{
			get
			{
				return false;
			}
		}
		/// <summary>
		/// Gets the unique, hierarchically qualified identifier for the server control.
		/// </summary>
		public override string UniqueID
		{
			get
			{
				return TPage.GetOptimizedUniqueId(ref this._uniqueId, base.UniqueID, !this.IsTemplated, 'C');
			}
		}
		/// <summary>
		/// Gets true if this control is part of a multiple instance templated; otherwise, false.
		/// </summary>
		[Browsable(false)]
		public bool IsTemplated
		{
			get
			{
				Control c = this;
				while (c != null)
				{
					if (c is MultipleInstanceTemplate.ContainerControl)
					{
						return true;
					}
					c = c.Parent;
				}
				return false;
			}
		}
		/// <summary>
		/// Gets or sets a comma-delimited list of properties that need to be serialized even if they are not used by client by default.
		/// </summary>
		public string SerializedProperties
		{
			get
			{
				return this._mpvSerializedProperties.Value;
			}
			set
			{
				this._mpvSerializedProperties.Value = value;
			}
		}
		/// <summary>
		/// Gets collection of properties that need to be serialized even if they are not used by client by default.
		/// </summary>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public List<string> SerializedPropertiesList
		{
			get
			{
				return this._mpvSerializedProperties.ValueList;
			}
		}
		///// <summary>
		///// Gets a flag indicating whether this control is actually rendered as UI on the page.
		///// </summary>
		///// <remarks>
		///// This property checks if any ascendant of this control is not rendered, too.
		///// </remarks>
		//public bool IsRendered
		//{
		//  get
		//  {
		//    if (!this.Rendered) return false;
		//    TControl parent = this.GetAscendant<TControl>();
		//    if (parent != null)
		//      return parent.IsRendered;

		//    return true;
		//  }
		//}
		#endregion
		#region METHODS
		/// <summary>
		/// Gets the current scenario for this control using the specified event name.
		/// </summary>
		/// <param name="eventName"></param>
		/// <returns></returns>
		public virtual PostScenario GetCurrentScenario(string eventName, string argument)
		{
			if (!this._events.ContainsKey(eventName) || !(this._events[eventName] is BaseServerEvent))
				throw new InvalidOperationException(string.Format("The control with unique ID '{0}' doesn't support the event '{1}'.", this.UniqueID, eventName));

			BaseServerEvent evt = this._events[eventName] as BaseServerEvent;
			return evt.PostScenario;
		}
		#endregion
		#endregion
		#region INTERNAL
		#region CONST/STATIC
		public const string StateFieldUniqueIdPostfix = "$",
			StateFieldClientIdPostfix = "_",
			ClientIdSeparator = "_",
			UniqueIdSeparator = "$";
		#endregion
		#region VARS
		/// <summary>
		/// All events for this control.
		/// </summary>
		/// <remarks>
		/// Declared internal because of LOMI. (lack of multiple inheritance)
		/// </remarks>
		internal Dictionary<string, ClientEvent> _events = new Dictionary<string, ClientEvent>();
		System.Web.UI.AttributeCollection _attributes = new System.Web.UI.AttributeCollection(new StateBag(true));
		Dictionary<string, object> _viewStateForReset = new Dictionary<string, object>();
		Dictionary<string, string> _attributesForReset = new Dictionary<string, string>();
		Dictionary<string, object> _controlStateForReset = new Dictionary<string, object>();
		string _uniqueId;
		StateBag _controlState = new StateBag();
		MultiPartValue _mpvSerializedProperties = new MultiPartValue();
		bool _visible;
		#endregion
		#region PROPS
		//internal new Dictionary<string, ClientEvent> Events
		//{
		//  get
		//  {
		//    return _events;
		//  }
		//}
		/// <summary>
		/// Gets the tag name of this control in string format. This is affected by the Tag property.
		/// </summary>
		protected string TagString { get; set; }
		internal StateBag _State
		{
			get
			{
				return this.ViewState;
			}
		}
		/// <summary>
		/// Gets the dictionary representing names and values of properties.
		/// </summary>
		protected internal StateBag ControlState
		{
			get
			{
				return this._controlState;
			}
		}
		#endregion
		#region methods
		#region RENDER
		/// <summary>
		/// Renders everything pertaining to this control.
		/// </summary>
		/// <param name="writer"></param>
		public override void RenderControl(HtmlTextWriter writer)
		{
#if DEBUG
			TPage.Log("TControl.RenderControl ID='" + this.ID + "' BEGIN");
#endif

			bool isRendered =
				this.Visible
				&&
				(
					this.Shown
					||
					(this.TPage != null && this.TPage.JavaScript != false)
				);

			if (isRendered && !this.get_IsDesignMode())
			{
				this.RenderState(writer);
			}

			if (isRendered
				||
				this.get_IsDesignMode())
			{
				Render(writer);
			}

#if DEBUG
			TPage.Log("TControl.RenderControl ID='" + this.ID + "' END");
#endif
		}
		/// <summary>
		/// Renders the HTML markup of this control.
		/// </summary>
		/// <param name="writer"></param>
		protected override void Render(HtmlTextWriter writer)
		{
			this.RenderBeginTag(writer);
			this.RenderContents(writer);
			this.RenderChildren(writer);
			this.RenderEndTag(writer);
		}
		/// <summary>
		/// Renders the hidden field with the state of this controls.
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void RenderState(HtmlTextWriter writer)
		{
#if DEBUG
			TPage.Log("TControl.RenderState ID='" + this.ID + "' BEGIN");
#endif

			using (StringWriter sw = new StringWriter())
			{
				JsonWriter jw = new JsonWriter(sw);
				bool any = false;
				jw.StartObject();
				foreach (BasePropertyDefinition pd in this.ClientProperties.Values)
				{
					any |= pd.SerializeValue(this, jw, true);
				}
				jw.EndObject();

				if (any)
				{
					writer.AddAttribute(HtmlTextWriterAttribute.Type, "hidden");
					writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + TControl.StateFieldClientIdPostfix);
					writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID + TControl.StateFieldUniqueIdPostfix);// 'S' is for State
					writer.AddAttribute(HtmlTextWriterAttribute.Value, sw.ToString());
					writer.RenderBeginTag(HtmlTextWriterTag.Input);
					writer.RenderEndTag();
				}
			}

#if DEBUG
			TPage.Log("TControl.RenderState ID='" + this.ID + "' END");
#endif
		}
		/// <summary>
		/// Renders the beginning tag of this control.
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void RenderBeginTag(HtmlTextWriter writer)
		{
#if DEBUG
			TPage.Log("TControl.RenderBeginTag ID='" + this.ID + "' BEGIN");
#endif

			AddAttributesToRender(writer);
			writer.RenderBeginTag(TagString);

#if DEBUG
			TPage.Log("TControl.RenderBeginTag ID='" + this.ID + "' END");
#endif
		}
		/// <summary>
		/// Add all attributes to render.
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void AddAttributesToRender(HtmlTextWriter writer)
		{
#if DEBUG
			TPage.Log("TControl.AddAttributesToRender ID='" + this.ID + "' BEGIN");
#endif

			if (!this.Shown)
			{
				if (!this.get_IsDesignMode())
				{
					this.Style[HtmlTextWriterStyle.Display] = "none";
				}
			}
			else
			{
				if (this.Style[HtmlTextWriterStyle.Display] == "none")
					this.Style.Remove(HtmlTextWriterStyle.Display);
			}

			if (this.IsIdAttributeRendered())
			{
				writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
			}
			if (this.IsNameAttributeRendered())
			{
				writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
			}

			if (!string.IsNullOrEmpty(ToolTip))
				writer.AddAttribute(HtmlTextWriterAttribute.Title, ToolTip);
			if (!Enabled)
				writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
			if (TabIndex != 0)
				writer.AddAttribute(HtmlTextWriterAttribute.Tabindex, TabIndex.ToString());

			foreach (string key in Attributes.Keys)
				writer.AddAttribute(key, Attributes[key]);


#if DEBUG
			TPage.Log("TControl.AddAttributesToRender ID='" + this.ID + "' END");
#endif
		}
		/// <summary>
		/// Returns true if the id attribute is required, otherwise false.
		/// </summary>
		/// <returns></returns>
		protected virtual bool IsIdAttributeRendered()
		{
			return true;
		}
		/// <summary>
		/// Returns true if the name attribute is required, otherwise false.
		/// </summary>
		/// <returns></returns>
		protected virtual bool IsNameAttributeRendered()
		{
			return TControl.IsFormElementTag(this.TagString);
		}
		/// <summary>
		/// Renders the contents of this control.
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void RenderContents(HtmlTextWriter writer)
		{
		}
		/// <summary>
		/// Renders the ending tag of this control.
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void RenderEndTag(HtmlTextWriter writer)
		{
			writer.RenderEndTag();
		}
		/// <summary>
		/// Outputs the needed part of the state of this control to the specified <see cref="JsonWriter"/>.
		/// </summary>
		/// <param name="jw"></param>
		/// <param name="cr"></param>
		internal void SaveState(JsonWriter jw, BaseControlReference cr)
		{
			jw.StartObject();

			this.SaveStateContents(jw, cr);

			jw.EndObject();
		}
		/// <summary>
		/// Outputs the needed part of the state of this control to the specified <see cref="JsonWriter"/>.
		/// </summary>
		/// <param name="jw"></param>
		/// <param name="cr"></param>
		internal virtual void SaveStateContents(JsonWriter jw, BaseControlReference cr)
		{
			jw.PropertyName("I");
			jw.Value(this.ClientID);

			if (cr.AnyProperties)
			{
				jw.PropertyName("P");
				jw.StartObject();

				foreach (string prName in MultiPartValue.GetActiveList(cr.PropertiesMode, cr.PropertiesList, this.ClientProperties.Keys))
				{
					BasePropertyDefinition pd = this.ClientProperties[prName];
					pd.SerializeValue(this, jw, false);
				}

				jw.EndObject();
			}
		}
		#endregion
		#region INIT
		/// <summary>
		/// Init.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);

			if (!this.get_IsDesignMode())
			{
				TPage.AddControl(this);

				IncludeCollection includes = new IncludeCollection();
				this.RegisterIncludes(includes);
				this.TPage.AddIncludes(includes);

#if DEBUG
				TPage.Log("TControl.OnInit ID='" + ID + "' END");
#endif
			}
		}
		/// <summary>
		/// Registers client resource files which are necessary for the proper operation of this control on the client.
		/// </summary>
		protected internal virtual void RegisterIncludes(IncludeCollection includes)
		{
			includes.Add(Script.BaseControl);
		}
		/// <summary>
		/// Saves the state of this control for being reset when re-using the page.
		/// </summary>
		protected internal virtual void SaveForReset()
		{
			foreach (string key in this.ViewState.Keys)
			{
				this._viewStateForReset[key] = SavedStateUtils.GetValueCopy(this.ViewState[key]);
			}
			foreach (string key in this.Attributes.Keys)
			{
				this._attributesForReset[key] = this.Attributes[key];
			}
			foreach (string propName in this._controlState.Keys)
			{
				this._controlStateForReset[propName] = this._controlState[propName];
			}
		}
		/// <summary>
		/// Resets the state of this control to the saved version when re-using the page.
		/// </summary>
		protected internal virtual void Reset()
		{
			this.ViewState.Clear();
			foreach (KeyValuePair<string, object> kv in this._viewStateForReset)
			{
				this.ViewState[kv.Key] = SavedStateUtils.GetValueCopy(kv.Value);
			}

			this.Attributes.Clear();
			foreach (KeyValuePair<string, string> kv in this._attributesForReset)
			{
				this.Attributes[kv.Key] = kv.Value;
			}

			this.ControlState.Clear();
			foreach (KeyValuePair<string, object> kvp in this._controlStateForReset)
			{
				this._controlState[kvp.Key] = kvp.Value;
			}
		}
		internal virtual void LoadState(BaseControlReference cr, NameValueCollection nvc)
		{
			string propsStringInput = nvc[this.UniqueID + TControl.StateFieldUniqueIdPostfix];
			if (string.IsNullOrEmpty(propsStringInput))
				return;

			using (StringReader sr = new StringReader(propsStringInput))
			{
				JsonReader jr = new JsonReader(sr);

				jr.Read(JsonToken.StartObject);

				Dictionary<string, BasePropertyDefinition> propsByShort = this.ClientPropertiesShort;

				int depth = jr.Depth;
				while (jr.TokenType == JsonToken.PropertyName)
				{
					string prShortName = (string)jr.Value; jr.Read();
					if (propsByShort.ContainsKey(prShortName))
					{
						BasePropertyDefinition pd = propsByShort[prShortName];
						string prName = pd.Name;
						if (MultiPartValue.IsIncluded(cr.PropertiesMode, cr.PropertiesList, prName))
						{
							pd.DeserializeValue(this, jr);
						}
					}

					do
						jr.Read();
					while (!(
						(jr.TokenType == JsonToken.EndObject && jr.Depth <= depth)
						||
						(jr.TokenType == JsonToken.PropertyName && jr.Depth <= depth + 1)));
				}

			}
		}
		#endregion
		#region IAttributeAccessor Members
		/// <summary>
		/// Returns the value of an attribute.
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		string IAttributeAccessor.GetAttribute(string key)
		{
			return Attributes[key];
		}
		/// <summary>
		/// Sets the value of an attribute.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="value"></param>
		void IAttributeAccessor.SetAttribute(string key, string value)
		{
			Attributes[key] = value;
		}

		#endregion
		#region EVENTS
		/// <summary>
		/// Returns (and initializes, if necessary) a event.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="name"></param>
		/// <returns></returns>
		protected T GetEvent<T>(string name) where T : ClientEvent, new()
		{
			if (!this._events.ContainsKey(name))
			{
				this._events[name] = new T();
				this._events[name].Set(this, name);
			}
			return (T)this._events[name];
		}
		/// <summary>
		/// Returns (and initializes, if necessary) a dual client-server (unlinked) event.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="name"></param>
		/// <returns></returns>
		protected DualEvent<T> GetDualEvent<T>(string name) where T : EventArgs
		{
			return this.GetEvent<DualEvent<T>>(name);
		}
		/// <summary>
		/// Returns (and initializes, if necessary) a client-server event.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="name"></param>
		/// <returns></returns>
		protected ServerEvent<T> GetServerEvent<T>(string name) where T : EventArgs
		{
			return this.GetEvent<ServerEvent<T>>(name);
		}
		/// <summary>
		/// Raises events.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="argument"></param>
		public virtual void RaiseEvent(string name, string argument)
		{

		}
		#endregion
		#region PROPERTIES
		/// <summary>
		/// Returns the value of the specified property.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="pName"></param>
		/// <returns></returns>
		protected T GetProperty<T>(string pName)
		{
			return ((PropertyDefinition<T>)this.ClientProperties[pName]).GetValue(this);
		}
		#endregion
		#endregion
		#endregion
	}
}